<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 3.8.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"yoursite.com","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="参考来自www.baeldung.com的多篇文章  Java Bean Validation的历史演变 原本以为JSR303就已经是够了，后面才发现这只是initial version，也就是Bean Validation 1.0； 后面又推出了JSR349（Bean Validation 1.1） 而最新版本是JSR380（Bean Validation 2.0）  依赖包在不使用第三方的框">
<meta name="keywords" content="Java,JSR303,JSR349,JSR380,Java Bean Validation">
<meta property="og:type" content="article">
<meta property="og:title" content="Java Bean Validation Basics">
<meta property="og:url" content="http://yoursite.com/2020/04/04/Java-Bean-Validation-Basics/index.html">
<meta property="og:site_name" content="Feng&#39;s Blog">
<meta property="og:description" content="参考来自www.baeldung.com的多篇文章  Java Bean Validation的历史演变 原本以为JSR303就已经是够了，后面才发现这只是initial version，也就是Bean Validation 1.0； 后面又推出了JSR349（Bean Validation 1.1） 而最新版本是JSR380（Bean Validation 2.0）  依赖包在不使用第三方的框">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://cdn.jsdelivr.net/gh/coding-by-feng/oss@master/uPic/0e8YJB.png">
<meta property="og:updated_time" content="2020-07-30T02:36:39.516Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java Bean Validation Basics">
<meta name="twitter:description" content="参考来自www.baeldung.com的多篇文章  Java Bean Validation的历史演变 原本以为JSR303就已经是够了，后面才发现这只是initial version，也就是Bean Validation 1.0； 后面又推出了JSR349（Bean Validation 1.1） 而最新版本是JSR380（Bean Validation 2.0）  依赖包在不使用第三方的框">
<meta name="twitter:image" content="https://cdn.jsdelivr.net/gh/coding-by-feng/oss@master/uPic/0e8YJB.png">

<link rel="canonical" href="http://yoursite.com/2020/04/04/Java-Bean-Validation-Basics/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-Hans'
  };
</script>

  <title>Java Bean Validation Basics | Feng's Blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Feng's Blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>Home</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>About</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>Tags</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>Categories</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>Archives</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-Hans">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/04/04/Java-Bean-Validation-Basics/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Fengorz">
      <meta itemprop="description" content="A Quiet Departure.">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Feng's Blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Java Bean Validation Basics
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2020-04-04 10:20:12" itemprop="dateCreated datePublished" datetime="2020-04-04T10:20:12+08:00">2020-04-04</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2020-07-30 10:36:39" itemprop="dateModified" datetime="2020-07-30T10:36:39+08:00">2020-07-30</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">In</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <blockquote>
<p>参考来自www.baeldung.com的多篇文章</p>
</blockquote>
<h1 id="Java-Bean-Validation的历史演变"><a href="#Java-Bean-Validation的历史演变" class="headerlink" title="Java Bean Validation的历史演变"></a>Java Bean Validation的历史演变</h1><ul>
<li>原本以为JSR303就已经是够了，后面才发现这只是initial version，也就是Bean Validation 1.0；</li>
<li>后面又推出了JSR349（Bean Validation 1.1）</li>
<li>而最新版本是<a href="https://jcp.org/en/jsr/detail?id=380" target="_blank" rel="noopener">JSR380</a>（<a href="https://beanvalidation.org/2.0/" target="_blank" rel="noopener">Bean Validation 2.0</a>）</li>
</ul>
<h1 id="依赖包"><a href="#依赖包" class="headerlink" title="依赖包"></a>依赖包</h1><p>在不使用第三方的框架提供的校验功能（比如Spring，Spring默认会引入依赖并对标准做了一些具体的实现）的情况下，想要使用Java Bean Validation的功能需要先引入标准API依赖(这里以2.0版本为准)：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;javax.validation&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;validation-api&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;2.0.0.Final&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure></p>
<p>除了引入标准之外，还要引入标准的实现：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.hibernate.validator&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;hibernate-validator&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;6.0.2.Final&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.hibernate.validator&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;hibernate-validator-annotation-processor&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;6.0.2.Final&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure></p>
<p>这里只是引入的hibernate的validator部分，没有引入持久化的那部分。<br>再引入el表达式的依赖：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;javax.el&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;javax.el-api&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;3.0.0&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br><span class="line"> </span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.glassfish.web&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;javax.el&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;2.2.6&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure></p>
<p>如果没有引入el表达式的依赖可能会报错：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HV000183: Unable to load ‘javax.el.ExpressionFactory&apos;. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead</span><br></pre></td></tr></table></figure></p>
<h1 id="可以通过Validator对Bean进行数据校验"><a href="#可以通过Validator对Bean进行数据校验" class="headerlink" title="可以通过Validator对Bean进行数据校验"></a>可以通过Validator对Bean进行数据校验</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">@Test</span><br><span class="line">public void test6() &#123;</span><br><span class="line">    FetchWordResultDTO fetchWordResultDTO = new FetchWordResultDTO();</span><br><span class="line">    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();</span><br><span class="line">    Validator validator = factory.getValidator();</span><br><span class="line">    Set&lt;ConstraintViolation&lt;FetchWordResultDTO&gt;&gt; results = validator.validate(fetchWordResultDTO);</span><br><span class="line">    for (ConstraintViolation&lt;FetchWordResultDTO&gt; result : results) &#123;</span><br><span class="line">        System.out.println(result.getPropertyPath());</span><br><span class="line">        System.out.println(result.getMessage());</span><br><span class="line">        System.out.println(result.getInvalidValue());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="校验注解"><a href="#校验注解" class="headerlink" title="校验注解"></a>校验注解</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">空检查</span><br><span class="line">@Null       验证对象是否为null</span><br><span class="line">@NotNull    验证对象是否不为null, 无法查检长度为0的字符串</span><br><span class="line">@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.</span><br><span class="line">@NotEmpty 检查约束元素是否为NULL或者是EMPTY.</span><br><span class="line"> </span><br><span class="line">Booelan检查</span><br><span class="line">@AssertTrue     验证 Boolean 对象是否为 true  </span><br><span class="line">@AssertFalse    验证 Boolean 对象是否为 false  </span><br><span class="line"> </span><br><span class="line">长度检查</span><br><span class="line">@Size(min=, max=) 验证对象（Array,Collection,Map,String）长度是否在给定的范围之内  </span><br><span class="line">@Length(min=, max=) Validates that the annotated string is between min and max included.</span><br><span class="line"> </span><br><span class="line">日期检查</span><br><span class="line">@Past           验证 Date 和 Calendar 对象是否在当前时间之前  </span><br><span class="line">@Future     验证 Date 和 Calendar 对象是否在当前时间之后  </span><br><span class="line">@Pattern    验证 String 对象是否符合正则表达式的规则</span><br><span class="line">@Past and @PastOrPresent – validate that a date value is in the past or the past including the present; can be applied to date types including those added in Java 8</span><br><span class="line">@Future and @FutureOrPresent – validates that a date value is in the future, or in the future including the present</span><br><span class="line"> </span><br><span class="line">数值检查，建议使用在Stirng,Integer类型，不建议使用在int类型上，因为表单值为“”时无法转换为int，但可以转换为Stirng为&quot;&quot;,Integer为null</span><br><span class="line">@Min            验证 Number 和 String 对象是否大等于指定的值  </span><br><span class="line">@Max            验证 Number 和 String 对象是否小等于指定的值  </span><br><span class="line">@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度</span><br><span class="line">@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度</span><br><span class="line">@Digits     验证 Number 和 String 的构成是否合法  </span><br><span class="line">@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字，interger指定整数精度，fraction指定小数精度。</span><br><span class="line">@Positive and @PositiveOrZero – apply to numeric values and validate that they are strictly positive, or positive including 0</span><br><span class="line">@Negative and @NegativeOrZero – apply to numeric values and validate that they are strictly negative, or negative including 0</span><br><span class="line"> </span><br><span class="line">@Range(min=, max=) 检查数字是否介于min和max之间.</span><br><span class="line">@Range(min=10000,max=50000,message=&quot;range.bean.wage&quot;)</span><br><span class="line">private BigDecimal wage;</span><br><span class="line"> </span><br><span class="line">@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)</span><br><span class="line">@CreditCardNumber信用卡验证</span><br><span class="line">@Email  验证是否是邮件地址，如果为null,不进行验证，算通过验证。</span><br><span class="line">@ScriptAssert(lang= ,script=, alias=)</span><br><span class="line">@URL(protocol=,host=, port=,regexp=, flags=)</span><br><span class="line">// 参考 https://www.cnblogs.com/yangzhilong/p/3724967.html</span><br></pre></td></tr></table></figure>
<h1 id="Validation-in-Spring-Boot"><a href="#Validation-in-Spring-Boot" class="headerlink" title="Validation in Spring Boot"></a>Validation in Spring Boot</h1><h2 id="利用-Valid对数据做优雅的校验"><a href="#利用-Valid对数据做优雅的校验" class="headerlink" title="利用@Valid对数据做优雅的校验"></a>利用@Valid对数据做优雅的校验</h2><p>校验异常会抛出MethodArgumentNotValidException，然后可以Spring的机制定义全局异常处理器。<br>Demo of Controller:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">@PostMapping(&quot;/storeFetchWordResult&quot;)</span><br><span class="line">public R storeFetchWordResult(@RequestBody @Valid FetchWordResultDTO fetchWordResultDTO) &#123;</span><br><span class="line">    // do something</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>全局异常处理器:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">@Slf4j</span><br><span class="line">@ControllerAdvice</span><br><span class="line">public class GlobalValidExceptionHandler &#123;</span><br><span class="line"></span><br><span class="line">    @ResponseBody</span><br><span class="line">    @ExceptionHandler(&#123;MethodArgumentNotValidException.class&#125;)</span><br><span class="line">    public R handleValidException(MethodArgumentNotValidException e)&#123;</span><br><span class="line">        //日志记录错误信息</span><br><span class="line">        log.error(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());</span><br><span class="line">        //将错误信息返回给前台</span><br><span class="line">        return R.failed(CommonConstants.FAIL, Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 优化之后的全局异常处理器</span><br><span class="line"></span><br><span class="line">@Slf4j</span><br><span class="line">@RestControllerAdvice</span><br><span class="line">public class GlobalExceptionHandler &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    @ExceptionHandler(&#123;MethodArgumentNotValidException.class&#125;)</span><br><span class="line">    @ResponseStatus(HttpStatus.BAD_REQUEST)</span><br><span class="line">    public R handleValidException(MethodArgumentNotValidException e)&#123;</span><br><span class="line">        //日志记录错误信息</span><br><span class="line">        final String errorMessage = EnhancedExceptionUtils.getLogMessage(e);</span><br><span class="line">        log.error(errorMessage);</span><br><span class="line">        //将错误信息返回给前台</span><br><span class="line">        return R.failed(CommonConstants.FAIL, errorMessage);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>某知名博客文章的全局异常处理器demo（多个字段的错误校验可以更加直观地展示出来）：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">@ResponseStatus(HttpStatus.BAD_REQUEST)</span><br><span class="line">@ExceptionHandler(MethodArgumentNotValidException.class)</span><br><span class="line">public Map&lt;String, String&gt; handleValidationExceptions(</span><br><span class="line">  MethodArgumentNotValidException ex) &#123;</span><br><span class="line">    Map&lt;String, String&gt; errors = new HashMap&lt;&gt;();</span><br><span class="line">    ex.getBindingResult().getAllErrors().forEach((error) -&gt; &#123;</span><br><span class="line">        String fieldName = ((FieldError) error).getField();</span><br><span class="line">        String errorMessage = error.getDefaultMessage();</span><br><span class="line">        errors.put(fieldName, errorMessage);</span><br><span class="line">    &#125;);</span><br><span class="line">    return errors;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="Validated-vs-Valid"><a href="#Validated-vs-Valid" class="headerlink" title="@Validated vs @Valid"></a>@Validated vs @Valid</h2><p><a href="https://blog.csdn.net/qq_27680317/article/details/79970590" target="_blank" rel="noopener">两者的区别</a><br><img src="https://cdn.jsdelivr.net/gh/coding-by-feng/oss@master/uPic/0e8YJB.png" alt></p>
<h2 id="Validated应用在ctl方法的参数的好处"><a href="#Validated应用在ctl方法的参数的好处" class="headerlink" title="@Validated应用在ctl方法的参数的好处"></a>@Validated应用在ctl方法的参数的好处</h2><p>可以直接在形参上注解：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">public ResponseMessage&lt;IPage&lt;PostPhoneInfo&gt;&gt; queryPage(@NotNull Long pageNum, @NotNull Long pageSize, PostPhoneInfo postPhoneInfo) &#123;</span><br><span class="line">    return ResponseMessage.success(postPhoneInfoService.queryPage(pageNum, pageSize, postPhoneInfo));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>之前我直接想直接采用注解校验入参，不想将校验逻辑带到业务中去，但是使用@Valid无法做到，而Spring封装好的@Validated可以做到。</p>
<h4 id="要注意的地方"><a href="#要注意的地方" class="headerlink" title="要注意的地方"></a>要注意的地方</h4><ul>
<li>校验注解是在方法入参上，则需要在该方法所在的类上添加 @org.springframework.validation.annotation.Validated 注解，在入参前或是在方法上添加启用校验注解都不生效。</li>
<li>如果ctl方法的入参是一个Java Bean承载，那么无需使用@NotNull校验，Spring模式会给一个空实例，@NotNull注解没有意义</li>
<li>使用@Validated分组的时候，比如只需要在某个ctl的方法上指定分组校验时，代码可以这样：<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 新增 or 更新</span><br><span class="line"> */</span><br><span class="line">@ApiOperation(notes = &quot;保存单条记录&quot;, value = &quot;保存查询单条记录&quot;)</span><br><span class="line">@PostMapping(&quot;/saveOne&quot;)</span><br><span class="line">@Validated(Default.class)</span><br><span class="line">public ResponseMessage&lt;Void&gt; saveOne(@Valid PostPhoneInfoVO postPhoneInfoVO) &#123;</span><br><span class="line">    postPhoneInfoService.saveOne(postPhoneInfoVO);</span><br><span class="line">    return ResponseMessage.success();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="Custom-Validation-MessageSource-in-Spring-Boot"><a href="#Custom-Validation-MessageSource-in-Spring-Boot" class="headerlink" title="Custom Validation MessageSource in Spring Boot"></a>Custom Validation MessageSource in Spring Boot</h2><p>MessageSource是Spring Boot很强大的一个特性，最为明显的是可以用于国际化处理。</p>
<h4 id="一个登陆表单的demo"><a href="#一个登陆表单的demo" class="headerlink" title="一个登陆表单的demo"></a>一个登陆表单的demo</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">public class LoginForm &#123;</span><br><span class="line"> </span><br><span class="line">    @NotEmpty(message = &quot;&#123;email.notempty&#125;&quot;)</span><br><span class="line">    @Email</span><br><span class="line">    private String email;</span><br><span class="line"> </span><br><span class="line">    @NotNull</span><br><span class="line">    private String password;</span><br><span class="line"> </span><br><span class="line">    // standard getter and setters</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="定义MessageSource-Bean"><a href="#定义MessageSource-Bean" class="headerlink" title="定义MessageSource Bean"></a>定义MessageSource Bean</h4><p>ReloadableResourceBundleMessageSource是最常用的MessageSource实现类<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">@Bean</span><br><span class="line">public MessageSource messageSource() &#123;</span><br><span class="line">    ReloadableResourceBundleMessageSource messageSource</span><br><span class="line">      = new ReloadableResourceBundleMessageSource();</span><br><span class="line">     </span><br><span class="line">    messageSource.setBasename(&quot;classpath:messages&quot;);</span><br><span class="line">    messageSource.setDefaultEncoding(&quot;UTF-8&quot;);</span><br><span class="line">    return messageSource;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="定义LocalValidatorFactoryBean来注册上面的MessageSource-Bean"><a href="#定义LocalValidatorFactoryBean来注册上面的MessageSource-Bean" class="headerlink" title="定义LocalValidatorFactoryBean来注册上面的MessageSource Bean"></a>定义LocalValidatorFactoryBean来注册上面的MessageSource Bean</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">@Bean</span><br><span class="line">public LocalValidatorFactoryBean getValidator() &#123;</span><br><span class="line">    LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();</span><br><span class="line">    bean.setValidationMessageSource(messageSource());</span><br><span class="line">    return bean;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="定义国际化配置文件"><a href="#定义国际化配置文件" class="headerlink" title="定义国际化配置文件"></a>定义国际化配置文件</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># messages.properties</span><br><span class="line">email.notempty=Please provide valid email id.</span><br><span class="line"># messages_fr.properties</span><br><span class="line">email.notempty=Veuillez fournir un identifiant de messagerie valide.</span><br></pre></td></tr></table></figure>
<h2 id="Method-Constraints-with-Bean-Validation-2-0"><a href="#Method-Constraints-with-Bean-Validation-2-0" class="headerlink" title="Method Constraints with Bean Validation 2.0"></a>Method Constraints with Bean Validation 2.0</h2><p>这个特性可以用于哪些比较复杂又常用的数据校验，而且校验逻辑是JSR380的注解不能实现的，所以需要自定义校验。</p>
<ul>
<li>Single-parameter Constraints</li>
<li>Cross-Parameter Constraints</li>
<li>return constraints</li>
</ul>
<h4 id="自定义校验注解实现Cross-Parameter-Constraints"><a href="#自定义校验注解实现Cross-Parameter-Constraints" class="headerlink" title="自定义校验注解实现Cross-Parameter Constraints"></a>自定义校验注解实现Cross-Parameter Constraints</h4><p>比如以下Demo：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">@ConsistentDateParameters</span><br><span class="line">public void createReservation(LocalDate begin, </span><br><span class="line">  LocalDate end, Customer customer) &#123;</span><br><span class="line">    // ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>如要有个业务场景是要求：begin必须比当前时间大，而且end必须比begin大的情况，那么使用JSR380的内置注解就无法实现了，所以要自定义校验注解和注解校验器。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">@Constraint(validatedBy = ConsistentDateParameterValidator.class)</span><br><span class="line">@Target(&#123; METHOD, CONSTRUCTOR &#125;)</span><br><span class="line">@Retention(RUNTIME)</span><br><span class="line">@Documented</span><br><span class="line">public @interface ConsistentDateParameters &#123;</span><br><span class="line"> </span><br><span class="line">    String message() default</span><br><span class="line">      &quot;End date must be after begin date and both must be in the future&quot;;</span><br><span class="line"> </span><br><span class="line">    Class&lt;?&gt;[] groups() default &#123;&#125;;</span><br><span class="line"> </span><br><span class="line">    Class&lt;? extends Payload&gt;[] payload() default &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">@SupportedValidationTarget(ValidationTarget.PARAMETERS)</span><br><span class="line">public class ConsistentDateParameterValidator </span><br><span class="line">  implements ConstraintValidator&lt;ConsistentDateParameters, Object[]&gt; &#123;</span><br><span class="line"> </span><br><span class="line">    @Override</span><br><span class="line">    public boolean isValid(</span><br><span class="line">      Object[] value, </span><br><span class="line">      ConstraintValidatorContext context) &#123;</span><br><span class="line">         </span><br><span class="line">        if (value[0] == null || value[1] == null) &#123;</span><br><span class="line">            return true;</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        if (!(value[0] instanceof LocalDate) </span><br><span class="line">          || !(value[1] instanceof LocalDate)) &#123;</span><br><span class="line">            throw new IllegalArgumentException(</span><br><span class="line">              &quot;Illegal method signature, expected two parameters of type LocalDate.&quot;);</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        return ((LocalDate) value[0]).isAfter(LocalDate.now()) </span><br><span class="line">          &amp;&amp; ((LocalDate) value[0]).isBefore((LocalDate) value[1]);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="自定义返回值的校验注解"><a href="#自定义返回值的校验注解" class="headerlink" title="自定义返回值的校验注解"></a>自定义返回值的校验注解</h4><p>比如要校验某个复杂的对象Reservation：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public class ReservationManagement &#123;</span><br><span class="line"> </span><br><span class="line">    @ValidReservation</span><br><span class="line">    public Reservation getReservationsById(int id) &#123;</span><br><span class="line">        return null;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>自定义注解，注意注解的范围可以是构造器CONSTRUCTOR：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">@Constraint(validatedBy = ValidReservationValidator.class)</span><br><span class="line">@Target(&#123; METHOD, CONSTRUCTOR &#125;)</span><br><span class="line">@Retention(RUNTIME)</span><br><span class="line">@Documented</span><br><span class="line">public @interface ValidReservation &#123;</span><br><span class="line">    String message() default &quot;End date must be after begin date &quot;</span><br><span class="line">      + &quot;and both must be in the future, room number must be bigger than 0&quot;;</span><br><span class="line"> </span><br><span class="line">    Class&lt;?&gt;[] groups() default &#123;&#125;;</span><br><span class="line"> </span><br><span class="line">    Class&lt;? extends Payload&gt;[] payload() default &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>校验器的具体实现：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">public class ValidReservationValidator</span><br><span class="line">  implements ConstraintValidator&lt;ValidReservation, Reservation&gt; &#123;</span><br><span class="line"> </span><br><span class="line">    @Override</span><br><span class="line">    public boolean isValid(</span><br><span class="line">      Reservation reservation, ConstraintValidatorContext context) &#123;</span><br><span class="line"> </span><br><span class="line">        if (reservation == null) &#123;</span><br><span class="line">            return true;</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        if (!(reservation instanceof Reservation)) &#123;</span><br><span class="line">            throw new IllegalArgumentException(&quot;Illegal method signature, &quot;</span><br><span class="line">            + &quot;expected parameter of type Reservation.&quot;);</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        if (reservation.getBegin() == null</span><br><span class="line">          || reservation.getEnd() == null</span><br><span class="line">          || reservation.getCustomer() == null) &#123;</span><br><span class="line">            return false;</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        return (reservation.getBegin().isAfter(LocalDate.now())</span><br><span class="line">          &amp;&amp; reservation.getBegin().isBefore(reservation.getEnd())</span><br><span class="line">          &amp;&amp; reservation.getRoom() &gt; 0);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>然后就可以在构造器方法上使用注解了：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">public class Reservation &#123;</span><br><span class="line"> </span><br><span class="line">    @ValidReservation</span><br><span class="line">    public Reservation(</span><br><span class="line">      LocalDate begin, </span><br><span class="line">      LocalDate end, </span><br><span class="line">      Customer customer, </span><br><span class="line">      int room) &#123;</span><br><span class="line">        this.begin = begin;</span><br><span class="line">        this.end = end;</span><br><span class="line">        this.customer = customer;</span><br><span class="line">        this.room = room;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    // properties, getters, and setters</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="级联校验-嵌套校验（Cascaded-Validation）"><a href="#级联校验-嵌套校验（Cascaded-Validation）" class="headerlink" title="级联校验 || 嵌套校验（Cascaded Validation）"></a>级联校验 || 嵌套校验（Cascaded Validation）</h4><p>想要校验对象里面的成员属性内部的相关校验，需要再成员属性声明加上@Valid注解，如：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">public class Reservation &#123;</span><br><span class="line"> </span><br><span class="line">    @Valid</span><br><span class="line">    private Customer customer;</span><br><span class="line">     </span><br><span class="line">    @Positive</span><br><span class="line">    private int room;</span><br><span class="line">     </span><br><span class="line">    // further properties, constructor, getters and setters</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h1 id="Validating-Container-Elements-with-Bean-Validation-2-0"><a href="#Validating-Container-Elements-with-Bean-Validation-2-0" class="headerlink" title="Validating Container Elements with Bean Validation 2.0"></a>Validating Container Elements with Bean Validation 2.0</h1><h2 id="注意内置的校验还可以用于集合的泛型定义"><a href="#注意内置的校验还可以用于集合的泛型定义" class="headerlink" title="注意内置的校验还可以用于集合的泛型定义"></a>注意内置的校验还可以用于集合的泛型定义</h2><p>比如下面Customer前面的@NotNull：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public class ReservationManagement &#123;</span><br><span class="line">    @NotNull</span><br><span class="line">    @Size(min = 1)</span><br><span class="line">    public List&lt;@NotNull Customer&gt; getAllCustomers() &#123;</span><br><span class="line">        return null;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>再比如：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">public class Customer &#123;    </span><br><span class="line">     List&lt;@NotBlank(message=&quot;Address must not be blank&quot;) String&gt; addresses;</span><br><span class="line">     </span><br><span class="line">    // standard getters, setters </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">public class CustomerMap &#123;</span><br><span class="line">     </span><br><span class="line">    private Map&lt;@Email String, @NotNull Customer&gt; customers;</span><br><span class="line">     </span><br><span class="line">    // standard getters, setters</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Optional-Values"><a href="#Optional-Values" class="headerlink" title="Optional Values"></a>Optional Values</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">private Integer age;</span><br><span class="line"> </span><br><span class="line">public Optional&lt;@Min(18) Integer&gt; getAge() &#123;</span><br><span class="line">    return Optional.ofNullable(age);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="非泛型容器的元素（Non-Generic-Container-Elements）"><a href="#非泛型容器的元素（Non-Generic-Container-Elements）" class="headerlink" title="非泛型容器的元素（Non-Generic Container Elements）"></a>非泛型容器的元素（Non-Generic Container Elements）</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">@Min(1)</span><br><span class="line">private OptionalInt numberOfOrders;</span><br></pre></td></tr></table></figure>
<h1 id="Problem-Solution"><a href="#Problem-Solution" class="headerlink" title="Problem Solution"></a>Problem Solution</h1><h2 id="HV000030-No-validator-could-be-found-for-type-java-lang-Integer"><a href="#HV000030-No-validator-could-be-found-for-type-java-lang-Integer" class="headerlink" title="HV000030: No validator could be found for type: java.lang.Integer."></a>HV000030: No validator could be found for type: java.lang.Integer.</h2><p><a href="https://blog.csdn.net/xiaobingtao/article/details/41866235" target="_blank" rel="noopener">https://blog.csdn.net/xiaobingtao/article/details/41866235</a></p>

    </div>

    
    
    

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Java/" rel="tag"># Java</a>
              <a href="/tags/JSR303/" rel="tag"># JSR303</a>
              <a href="/tags/JSR349/" rel="tag"># JSR349</a>
              <a href="/tags/JSR380/" rel="tag"># JSR380</a>
              <a href="/tags/Java-Bean-Validation/" rel="tag"># Java Bean Validation</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/04/02/Spring系列之Cache/" rel="prev" title="Spring系列之Cache">
      <i class="fa fa-chevron-left"></i> Spring系列之Cache
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/04/06/正则表达式汇总/" rel="next" title="正则表达式汇总">
      正则表达式汇总 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Java-Bean-Validation的历史演变"><span class="nav-number">1.</span> <span class="nav-text">Java Bean Validation的历史演变</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#依赖包"><span class="nav-number">2.</span> <span class="nav-text">依赖包</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#可以通过Validator对Bean进行数据校验"><span class="nav-number">3.</span> <span class="nav-text">可以通过Validator对Bean进行数据校验</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#校验注解"><span class="nav-number">4.</span> <span class="nav-text">校验注解</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Validation-in-Spring-Boot"><span class="nav-number">5.</span> <span class="nav-text">Validation in Spring Boot</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#利用-Valid对数据做优雅的校验"><span class="nav-number">5.1.</span> <span class="nav-text">利用@Valid对数据做优雅的校验</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Validated-vs-Valid"><span class="nav-number">5.2.</span> <span class="nav-text">@Validated vs @Valid</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Validated应用在ctl方法的参数的好处"><span class="nav-number">5.3.</span> <span class="nav-text">@Validated应用在ctl方法的参数的好处</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#要注意的地方"><span class="nav-number">5.3.0.1.</span> <span class="nav-text">要注意的地方</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Custom-Validation-MessageSource-in-Spring-Boot"><span class="nav-number">5.4.</span> <span class="nav-text">Custom Validation MessageSource in Spring Boot</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#一个登陆表单的demo"><span class="nav-number">5.4.0.1.</span> <span class="nav-text">一个登陆表单的demo</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#定义MessageSource-Bean"><span class="nav-number">5.4.0.2.</span> <span class="nav-text">定义MessageSource Bean</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#定义LocalValidatorFactoryBean来注册上面的MessageSource-Bean"><span class="nav-number">5.4.0.3.</span> <span class="nav-text">定义LocalValidatorFactoryBean来注册上面的MessageSource Bean</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#定义国际化配置文件"><span class="nav-number">5.4.0.4.</span> <span class="nav-text">定义国际化配置文件</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Method-Constraints-with-Bean-Validation-2-0"><span class="nav-number">5.5.</span> <span class="nav-text">Method Constraints with Bean Validation 2.0</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#自定义校验注解实现Cross-Parameter-Constraints"><span class="nav-number">5.5.0.1.</span> <span class="nav-text">自定义校验注解实现Cross-Parameter Constraints</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#自定义返回值的校验注解"><span class="nav-number">5.5.0.2.</span> <span class="nav-text">自定义返回值的校验注解</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#级联校验-嵌套校验（Cascaded-Validation）"><span class="nav-number">5.5.0.3.</span> <span class="nav-text">级联校验 || 嵌套校验（Cascaded Validation）</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Validating-Container-Elements-with-Bean-Validation-2-0"><span class="nav-number">6.</span> <span class="nav-text">Validating Container Elements with Bean Validation 2.0</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#注意内置的校验还可以用于集合的泛型定义"><span class="nav-number">6.1.</span> <span class="nav-text">注意内置的校验还可以用于集合的泛型定义</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Optional-Values"><span class="nav-number">6.2.</span> <span class="nav-text">Optional Values</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#非泛型容器的元素（Non-Generic-Container-Elements）"><span class="nav-number">6.3.</span> <span class="nav-text">非泛型容器的元素（Non-Generic Container Elements）</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Problem-Solution"><span class="nav-number">7.</span> <span class="nav-text">Problem Solution</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#HV000030-No-validator-could-be-found-for-type-java-lang-Integer"><span class="nav-number">7.1.</span> <span class="nav-text">HV000030: No validator could be found for type: java.lang.Integer.</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">Fengorz</p>
  <div class="site-description" itemprop="description">A Quiet Departure.</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">125</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">68</span>
        <span class="site-state-item-name">categories</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">87</span>
        <span class="site-state-item-name">tags</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Fengorz</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a>
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>
<script src="/js/utils.js"></script><script src="/js/motion.js"></script>
<script src="/js/schemes/pisces.js"></script>
<script src="/js/next-boot.js"></script>



  















  

  

</body>
</html>
